package com.thm.tfast.modules.sys.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.thm.tfast.core.enums.DeleteFlagEnum;
import com.thm.tfast.core.exception.Asserts;
import com.thm.tfast.core.sevruity.domain.SysUserDetails;
import com.thm.tfast.core.utils.SecurityUtil;
import com.thm.tfast.modules.sys.mapper.SysDictItemMapper;
import com.thm.tfast.modules.sys.model.SysDictItem;
import com.thm.tfast.modules.sys.model.dto.dict.DictItemInsertDto;
import com.thm.tfast.modules.sys.model.dto.dict.DictItemUpdateDto;
import com.thm.tfast.modules.sys.model.vo.dict.DictItemVo;
import com.thm.tfast.modules.sys.service.SysCacheService;
import com.thm.tfast.modules.sys.service.SysDictItemService;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;

/**
 * <p>
 * 字典项表 服务实现类
 * </p>
 *
 * @author THM
 * @since 2022-10-31
 */
@Service
public class SysDictItemServiceImpl extends ServiceImpl<SysDictItemMapper, SysDictItem> implements SysDictItemService {

    @Resource
    private SysCacheService sysCacheService;

    @PostConstruct
    private void initDictCache(){
        CompletableFuture.runAsync(()->{
            List<SysDictItem> sysDictItemList = this.list(Wrappers
                    .<SysDictItem>lambdaQuery()
                    .ne(SysDictItem::getDelFlag, DeleteFlagEnum.DELETED.getCode()));
            if (CollectionUtil.isNotEmpty(sysDictItemList)){
                Map<String, List<SysDictItem>> dictMap = sysDictItemList.stream().collect(Collectors.groupingBy(SysDictItem::getType));
                Iterator<Map.Entry<String, List<SysDictItem>>> iterator = dictMap.entrySet().iterator();
                while (iterator.hasNext()){
                    Map.Entry<String, List<SysDictItem>> next = iterator.next();
                    sysCacheService.delDict(next.getKey());
                    sysCacheService.setDict(next.getKey(),BeanUtil.copyToList(next.getValue(), DictItemVo.class));
                }
            }
        });
    }

    @Override
    public Page<SysDictItem> page(String keyword, Long dictId, Integer pageNum, Integer pageSize) {
        Page<SysDictItem> page = new Page<>(pageNum,pageSize);
        LambdaQueryWrapper<SysDictItem> wrapper = Wrappers.lambdaQuery();
        if (StrUtil.isNotEmpty(keyword)){
            wrapper.like(SysDictItem::getType,keyword)
                    .or()
                    .like(SysDictItem::getLabel,keyword);
        }
        if (Objects.nonNull(dictId)){
            wrapper.eq(SysDictItem::getDictId,dictId);
        }
        wrapper.eq(SysDictItem::getDelFlag,DeleteFlagEnum.UNDELETE.getCode())
                .orderByAsc(SysDictItem::getSort);
        return this.page(page,wrapper);
    }

    @Override
    public Long insert(DictItemInsertDto dto) {
        SysDictItem sysDictItem = this.getOne(Wrappers
                .<SysDictItem>lambdaQuery()
                .eq(SysDictItem::getDictId, dto.getDictId())
                .eq(SysDictItem::getValue, dto.getValue()));
        if (Objects.nonNull(sysDictItem)){
            Asserts.fail(sysDictItem.getType() + "中已经存在值为" + sysDictItem.getValue() + "的字典项");
        }
        sysDictItem = BeanUtil.toBean(dto,SysDictItem.class);
        SysUserDetails currentUser = SecurityUtil.getCurrentUser();
        sysDictItem.setCreateUser(currentUser.getUserId());
        sysDictItem.setCreateTime(currentUser.getDate());
        sysDictItem.setUpdateUser(currentUser.getUserId());
        sysDictItem.setUpdateTime(currentUser.getDate());
        this.save(sysDictItem);
        return sysDictItem.getId();
    }

    @Override
    public Boolean update(DictItemUpdateDto dto) {
        SysDictItem dictItem = this.getById(dto.getId());
        if (Objects.isNull(dictItem)){
            Asserts.fail("字典项信息不存在");
        }
        SysDictItem sysDictItem = BeanUtil.toBean(dto, SysDictItem.class);
        SysUserDetails currentUser = SecurityUtil.getCurrentUser();
        sysDictItem.setUpdateUser(currentUser.getUserId());
        sysDictItem.setUpdateTime(currentUser.getDate());
        //删除字典相关缓存
        delDictCache(dictItem.getType());
        return this.updateById(sysDictItem);
    }

    @Override
    public Boolean delete(Long dictItemId) {
        SysDictItem sysDictItem = this.getById(dictItemId);
        if (Objects.isNull(sysDictItem)){
            Asserts.fail("字典项信息不存在");
        }
        SysUserDetails currentUser = SecurityUtil.getCurrentUser();
        sysDictItem.setUpdateUser(currentUser.getUserId());
        sysDictItem.setUpdateTime(currentUser.getDate());
        sysDictItem.setDelFlag(DeleteFlagEnum.DELETED.getCode());
        //删除与菜单相关缓存
        delDictCache(sysDictItem.getType());
        return this.updateById(sysDictItem);
    }

    @Override
    public void refresh() {
        this.initDictCache();
    }

    @Override
    public List<DictItemVo> getDict(String type) {
        List<DictItemVo> dicts = sysCacheService.getDict(type);
        if (CollectionUtil.isEmpty(dicts)){
            List<SysDictItem> sysDictItemList = this.list(Wrappers
                    .<SysDictItem>lambdaQuery()
                    .eq(SysDictItem::getType, type));
            if (CollectionUtil.isNotEmpty(sysDictItemList)){
                dicts = BeanUtil.copyToList(sysDictItemList,DictItemVo.class);
                sysCacheService.setDict(type,BeanUtil.copyToList(sysDictItemList,DictItemVo.class));
            } else {
                Asserts.fail(type + "类型字典不存在");
            }
        }
        return dicts;
    }

    @Override
    public void delDictCache(String type) {
        sysCacheService.delDict(type);
    }
}
